library(here)
library(readxl)
library(dplyr)
library(BelgiumMaps.StatBel)
library(sf)
library(tmap)
library(leaflet)
library(leaflet.minicharts)
library(htmltools)
library(ggplot2)
library(stringr)
library(htmlwidgets)
library(here)

1 Read in dynam and spatial data

dynam.prov = read_excel(
    '20180425_dynam_be_jobdata_origineel.xlsx', 'Sheet2',
    skip = 1,  col_names = c(
      'province_lbl', 'province_nis_code', 
      'bruto_toename_absoluut', 'bruto_afname_absoluut', 'netto_absoluut', 'delme',
      'delmetoo', 'bruto_toename_graad', 'bruto_afname_graad', 'netto_graad', 'delmetootoo', 'werkzaamheidsgraad')) %>%
  select(-delme, -delmetoo, -delmetootoo)
dynam.prov
dynam.prov  <- dynam.prov %>% 
  mutate(
    province_lbl = case_when(
      province_lbl == 'Brussels Hoofdstedelijk Gewest' ~ 'Brussel',
      TRUE ~ province_lbl))
dynam.prov = dynam.prov %>%
  mutate(
    province_lbl_pct = str_c(province_lbl, '    ', str_sub(as.character(netto_graad*100),1,4), '%'))
province_lbl_ordered <- dynam.prov %>%
  arrange(netto_graad) %>% # rangschik procentuele of absolute groei
  # arrange(absoluut_netto) %>%
  pull(province_lbl_pct)
    
dynam.prov = dynam.prov %>%
    mutate(province_lbl_pct = factor(province_lbl_pct, levels = province_lbl_ordered))
dynam.prov = dynam.prov %>%
  mutate(
    netto_pct = netto_graad*100,
    bruto_toename_pct = bruto_toename_graad*100,
    bruto_afname_pct = bruto_afname_graad*100,
    bruto_afname_absoluut_neg = bruto_afname_absoluut*-1)
data('BE_ADMIN_PROVINCE') 
data("BE_ADMIN_REGION")
# convert to simple features dataset-structure
provinces = st_as_sf(BE_ADMIN_PROVINCE) 
regions = st_as_sf(BE_ADMIN_REGION) 
# Spatial object for Brussels-region is not included in provences, add from region
provinces = rbind(
  provinces %>% select(CD_PROV_REFNIS, TX_PROV_DESCR_NL),
  regions %>%
    filter(TX_RGN_DESCR_NL == "Brussels Hoofdstedelijk Gewest") %>%
    mutate(CD_RGN_REFNIS = '04000') %>%
    select(
      CD_PROV_REFNIS = CD_RGN_REFNIS,
      TX_PROV_DESCR_NL = TX_RGN_DESCR_NL))
provinces = provinces %>%
  mutate(CD_PROV_REFNIS = as.character(CD_PROV_REFNIS)) %>%
  left_join(dynam.prov, c('CD_PROV_REFNIS' = 'province_nis_code'))
# get centroid coordinates for each province to plot barchart there
provinces_coords = as_tibble(st_coordinates(st_centroid(provinces)))
names(provinces_coords) <- c('centroid_long', 'centroid_lat')
provinces <- bind_cols(provinces, provinces_coords)

2 Descriptive graphs

2.1 Overlapping barchart example

# Overlapping barcharts:
# http://stephanieevergreen.com/overlapping-bars/
# https://gist.github.com/hrbrmstr/035f998517de2384e9962cff7df874bd
# 
gg <- ggplot(data=dynam.prov, aes(y=province_lbl_pct, yend=province_lbl_pct))
gg <- gg + geom_segment(aes(x=bruto_afname_absoluut, xend=0, color="Jobverlies"), size=10)
gg <- gg + geom_segment(aes(x=bruto_toename_absoluut, xend=0, color="Jobgroei"), size=5)
gg <- gg + scale_x_continuous(labels=function(x) format(x, decimal.mark = ',', big.mark = ".", scientific = FALSE))
gg <- gg + scale_color_manual(name=NULL, values=c(Jobverlies="#bebebf", Jobgroei="#1074bc"))
gg <- gg + guides(color=guide_legend(keywidth=0, override.aes=list(size=4)))
gg <- gg + labs(
  x=NULL, y=NULL,
  title="Alle provincies kennen een netto jobaangroei, met de grootste\nprocentuele groei in Namen",
  subtitle = 'Procentuele en absolute jobevolutie per provincie, 2016-2017',
  caption="Bron: HIVA-KU Leuven | DynaM | dynamresearch.be")
gg <- gg + theme_minimal()
gg <- gg + theme(axis.text.x=element_text(margin=margin(t=0)))
gg <- gg + theme(axis.text.y=element_text(margin=margin(r=-10)))
gg <- gg + theme(panel.grid.minor=element_blank())
gg <- gg + theme(panel.grid.major.y=element_blank())
gg <- gg + theme(plot.title=element_text(face="bold"))
gg <- gg + theme(plot.margin=margin(20,20,20,20))
gg <- gg + theme(plot.caption=element_text(size=8, margin=margin(t=10, r=0)))
gg <- gg + theme(legend.position=c(0.8, 0.9))
gg <- gg + theme(legend.direction="vertical")
gg <- gg + theme(legend.background=element_rect(fill="white", color="white"))
gg

3 Static map visualisations

3.1 Inkleuren bruto toename

tm_shape(provinces) +
  tm_polygons(col = 'bruto_toename_pct', palette = 'Greens', border.col = 'white', title = 'Bruto jobtoename (%)')

3.2 Inkleuren bruto afname

tm_shape(provinces) +
  tm_polygons(col = 'bruto_afname_pct', palette = 'Reds', border.col = 'white', title = 'Bruto jobafname (%)')

3.3 Inkleuren netto evolutie

tm_shape(provinces) +
  tm_polygons(col = 'netto_pct', palette = 'Greens', border.col = 'white', title = 'Netto jobevolutie (%)')

3.4 Inkleuren bruto jobtoename + exact cijfer

tm_shape(provinces %>% mutate(bruto_toename_pct = round(bruto_toename_pct, 2))) +
  tm_polygons(col = 'bruto_toename_pct', palette = 'Greens', border.col = 'white', title = 'Bruto jobtoename (%)') +
  tm_text('bruto_toename_pct', size= .7)

3.5 Inkleuren bruto jobafname + exact cijfer

tm_shape(provinces %>% mutate(bruto_afname_pct = round(bruto_afname_pct, 2))) +
  tm_polygons(col = 'bruto_afname_pct', palette = 'Reds', border.col = 'white', title = 'Bruto jobafname (%)') +
  tm_text('bruto_afname_pct', size= .7)

3.6 Inkleuren netto evolutie + exact cijfer

tm_shape(provinces %>% mutate(netto_pct = round(netto_pct, 2))) +
  tm_polygons(col = 'netto_pct', palette = 'Greens', border.col = 'white', title = 'Netto jobevolutie (%)') +
  tm_text('netto_pct', size= .7)

4 Interactive map visualisations

4.1 Achtergrondkleur netto-evolutie (%) + cijfers in mouse-over popup

bins <- c(0.0, 0.5, 1, 1.5, 2.0, 2.5)
pal_greens_netto <- colorBin("Greens", domain = provinces$netto_pct, bins = bins)
provinces <- provinces %>%
  mutate(popup_lbl = str_glue("<h3>{province_lbl}</h3><br /><b>Jobtoename: </b>{netto_pct}"))
labels <- sprintf(
  "<strong>%s</strong><br/>Jobtoename: %1.2f%%<br/>Jobafname: %1.2f%%<br/>Netto evolutie: %1.2f%%<br/>",
  provinces$province_lbl, provinces$bruto_toename_pct, provinces$bruto_afname_pct, provinces$netto_pct
) %>% lapply(htmltools::HTML)
map_title <- tags$div(
  HTML('<b>Netto jobevolutie per provincie, 2015-2016 (<a href="https://dynamresearch.be/">dynaM</a>)</b>')
)  
m.dynam.prov.netto.hover <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_netto(netto_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Jobevolutie (%)',
    pal = pal_greens_netto, values = ~netto_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.netto.hover

4.2 Achtergrondkleur bruto-toename (%) + cijfers in mouse-over popup

bins <- c(4, 5, 6, 7, 8)
pal_greens_toename <- colorBin("Greens", domain = provinces$bruto_toename_pct, bins = bins)
map_title <- tags$div(
  HTML('<b>Bruto jobtoename per provincie, 2015-2016 (<a href="https://dynamresearch.be/">dynaM</a>)</b>')
)
m.dynam.prov.toename.hover <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_toename(bruto_toename_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Bruto jobtoename (%)',
    pal = pal_greens_toename, values = ~bruto_toename_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.toename.hover

4.3 Achtergrondkleur bruto-afname (%) + cijfers in mouse-over popup

bins <- c(4, 5, 6, 7, 8)
pal_greens_afname <- colorBin("Reds", domain = provinces$bruto_toename_pct, bins = bins)
map_title <- tags$div(
  HTML('<b>Bruto jobafname per provincie, 2015-2016 (<a href="https://dynamresearch.be/">dynaM</a>)</b>')
)
m.dynam.prov.afname.hover <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_afname(bruto_toename_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Bruto jobafname (%)',
    pal = pal_greens_afname, values = ~bruto_toename_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.afname.hover

4.4 Achtergrondkleur netto-evolutie (%) + cijfers in mouse-over popup + netto-cijfer weergeven

bins <- c(0.0, 0.5, 1, 1.5, 2.0, 2.5)
pal_greens_netto <- colorBin("Greens", domain = provinces$netto_pct, bins = bins)
provinces <- provinces %>%
  mutate(popup_lbl = str_glue("<h3>{province_lbl}</h3><br /><b>Jobtoename: </b>{netto_pct}"))
labels <- sprintf(
  "<strong>%s</strong><br/>Jobtoename: %1.2f%%<br/>Jobafname: %1.2f%%<br/>Netto evolutie: %1.2f%%<br/>",
  provinces$province_lbl, provinces$bruto_toename_pct, provinces$bruto_afname_pct, provinces$netto_pct
) %>% lapply(htmltools::HTML)
map_title <- tags$div(
  HTML('<b>Netto jobevolutie per provincie, 2015-2016 (<a href="https://dynamresearch.be/">dynaM</a>)</b>')
)  
m.dynam.prov.netto.hover.number <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_netto(netto_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Jobevolutie (%)',
    pal = pal_greens_netto, values = ~netto_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.netto.hover.number = m.dynam.prov.netto.hover.number %>%
  addLabelOnlyMarkers(lng = ~centroid_long, lat = ~centroid_lat, 
                      label =  ~as.character(round(netto_pct,2)), 
                      labelOptions = labelOptions(noHide = T, direction = 'top', textOnly = T))
m.dynam.prov.netto.hover.number

4.5 Achtergrond nettoevolutie + clickable barchart met absolute evolutie

pal <- colorBin("Greens", domain = dynam.prov$netto_pct)
d.abs = dynam.prov %>%
  select(
    'Jobgroei' = bruto_toename_absoluut,
    'Jobverlies' = bruto_afname_absoluut_neg,
    'Netto jobevolutie' = netto_absoluut)
d.pct = dynam.prov %>%
  mutate(
    bruto_toename_pct = round(bruto_toename_pct,2),
    bruto_afname_pct = round(bruto_afname_pct*-1,2),
    netto_pct = round(netto_pct,2)) %>%
select(
  'Jobgroei' = bruto_toename_pct,
  'Jobverlies' = bruto_afname_pct,
  'Netto jobevolutie' = netto_pct)
m.prov = leaflet(provinces, width = '100%') %>% 
  # add grey arrondissement polygons w/t white border
  addPolygons(
    weight = 2,
    opacity = 1,
    dashArray = "3",
    fillColor = ~pal(netto_pct), color = 'white') %>% 
  addLegend(pal = pal, values = ~netto_absoluut, opacity = 0.7,
            title = 'Netto jobevolutie (%)',
  position = "bottomright")
colors <- c("#7cae00", "#f8766d", "#c77cff")
m.prov = m.prov %>%
  addMinicharts(
    provinces_coords$centroid_long, provinces_coords$centroid_lat,
    chartdata = d.abs,
    colorPalette = colors,
    width = 45, height = 45)
map_title <- tags$div(
   HTML('<b>Bruto en netto jobevolutie per provincie, 2017-2018 (<a href="https://dynamresearch.be/">DynaM</a>)</b>')
 )  
m.prov = m.prov %>% 
  addControl(map_title, position = "bottomleft")
m.prov
m.dyam.bar.netto.pct = leaflet(provinces, width = '100%') %>% 
  # add grey arrondissement polygons w/t white border
  addPolygons(
    weight = 2,
    opacity = 1,
    dashArray = "3",
    fillColor = ~pal(netto_pct), color = 'white') %>% 
  addLegend(pal = pal, values = ~netto_pct, opacity = 0.7,
            title = 'Netto jobevolutie (%)',
  position = "bottomright")
colors <- c("#7cae00", "#f8766d", "#c77cff")
m.dyam.bar.netto.pct = m.dyam.bar.netto.pct %>%
  addMinicharts(
    provinces_coords$centroid_long, provinces_coords$centroid_lat,
    chartdata = d.pct,
    colorPalette = colors,
    width = 45, height = 45)
map_title <- tags$div(
   HTML('<b>Bruto en netto jobevolutie per provincie, 2017-2018 (<a href="https://dynamresearch.be/">DynaM</a>)</b>')
 )  
m.dyam.bar.netto.pct = m.dyam.bar.netto.pct %>% 
  addControl(map_title, position = "bottomleft")
m.dyam.bar.netto.pct
# saveWidget(
#   m.dynam.prov, file = here::here('dynam_jobevolution', 'dynam_netto_map_selfcontained.html'), 
#   selfcontained = TRUE,
#   background = 'white')
# 
# saveWidget(
#   m.dynam.prov, file = here::here('dynam_jobevolution', 'dynam_netto_map_notselfcontained.html'), 
#   selfcontained = FALSE,
#   background = 'white')
LS0tDQp0aXRsZTogIkR5bmFtIGpvYmV2b2x1dGllIGthYXJ0amVzIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazogDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShoZXJlKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShCZWxnaXVtTWFwcy5TdGF0QmVsKQ0KbGlicmFyeShzZikNCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkobGVhZmxldC5taW5pY2hhcnRzKQ0KbGlicmFyeShodG1sdG9vbHMpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGh0bWx3aWRnZXRzKQ0KbGlicmFyeShoZXJlKQ0KYGBgDQoNCiMgUmVhZCBpbiBkeW5hbSBhbmQgc3BhdGlhbCBkYXRhDQoNCmBgYHtyfQ0KZHluYW0ucHJvdiA9IHJlYWRfZXhjZWwoDQogICAgJzIwMTgwNDI1X2R5bmFtX2JlX2pvYmRhdGFfb3JpZ2luZWVsLnhsc3gnLCAnU2hlZXQyJywNCiAgICBza2lwID0gMSwgIGNvbF9uYW1lcyA9IGMoDQogICAgICAncHJvdmluY2VfbGJsJywgJ3Byb3ZpbmNlX25pc19jb2RlJywgDQogICAgICAnYnJ1dG9fdG9lbmFtZV9hYnNvbHV1dCcsICdicnV0b19hZm5hbWVfYWJzb2x1dXQnLCAnbmV0dG9fYWJzb2x1dXQnLCAnZGVsbWUnLA0KICAgICAgJ2RlbG1ldG9vJywgJ2JydXRvX3RvZW5hbWVfZ3JhYWQnLCAnYnJ1dG9fYWZuYW1lX2dyYWFkJywgJ25ldHRvX2dyYWFkJywgJ2RlbG1ldG9vdG9vJywgJ3dlcmt6YWFtaGVpZHNncmFhZCcpKSAlPiUNCiAgc2VsZWN0KC1kZWxtZSwgLWRlbG1ldG9vLCAtZGVsbWV0b290b28pDQpgYGANCg0KYGBge3J9DQpkeW5hbS5wcm92DQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpkeW5hbS5wcm92ICA8LSBkeW5hbS5wcm92ICU+JSANCiAgbXV0YXRlKA0KICAgIHByb3ZpbmNlX2xibCA9IGNhc2Vfd2hlbigNCiAgICAgIHByb3ZpbmNlX2xibCA9PSAnQnJ1c3NlbHMgSG9vZmRzdGVkZWxpamsgR2V3ZXN0JyB+ICdCcnVzc2VsJywNCiAgICAgIFRSVUUgfiBwcm92aW5jZV9sYmwpKQ0KDQpkeW5hbS5wcm92ID0gZHluYW0ucHJvdiAlPiUNCiAgbXV0YXRlKA0KICAgIHByb3ZpbmNlX2xibF9wY3QgPSBzdHJfYyhwcm92aW5jZV9sYmwsICcgICAgJywgc3RyX3N1Yihhcy5jaGFyYWN0ZXIobmV0dG9fZ3JhYWQqMTAwKSwxLDQpLCAnJScpKQ0KDQpwcm92aW5jZV9sYmxfb3JkZXJlZCA8LSBkeW5hbS5wcm92ICU+JQ0KICBhcnJhbmdlKG5ldHRvX2dyYWFkKSAlPiUgIyByYW5nc2NoaWsgcHJvY2VudHVlbGUgb2YgYWJzb2x1dGUgZ3JvZWkNCiAgIyBhcnJhbmdlKGFic29sdXV0X25ldHRvKSAlPiUNCiAgcHVsbChwcm92aW5jZV9sYmxfcGN0KQ0KDQogICAgDQpkeW5hbS5wcm92ID0gZHluYW0ucHJvdiAlPiUNCiAgICBtdXRhdGUocHJvdmluY2VfbGJsX3BjdCA9IGZhY3Rvcihwcm92aW5jZV9sYmxfcGN0LCBsZXZlbHMgPSBwcm92aW5jZV9sYmxfb3JkZXJlZCkpDQoNCmR5bmFtLnByb3YgPSBkeW5hbS5wcm92ICU+JQ0KICBtdXRhdGUoDQogICAgbmV0dG9fcGN0ID0gbmV0dG9fZ3JhYWQqMTAwLA0KICAgIGJydXRvX3RvZW5hbWVfcGN0ID0gYnJ1dG9fdG9lbmFtZV9ncmFhZCoxMDAsDQogICAgYnJ1dG9fYWZuYW1lX3BjdCA9IGJydXRvX2FmbmFtZV9ncmFhZCoxMDAsDQogICAgYnJ1dG9fYWZuYW1lX2Fic29sdXV0X25lZyA9IGJydXRvX2FmbmFtZV9hYnNvbHV1dCotMSkNCg0KYGBgDQoNCg0KYGBge3J9DQpkYXRhKCdCRV9BRE1JTl9QUk9WSU5DRScpIA0KZGF0YSgiQkVfQURNSU5fUkVHSU9OIikNCg0KIyBjb252ZXJ0IHRvIHNpbXBsZSBmZWF0dXJlcyBkYXRhc2V0LXN0cnVjdHVyZQ0KcHJvdmluY2VzID0gc3RfYXNfc2YoQkVfQURNSU5fUFJPVklOQ0UpIA0KcmVnaW9ucyA9IHN0X2FzX3NmKEJFX0FETUlOX1JFR0lPTikgDQoNCiMgU3BhdGlhbCBvYmplY3QgZm9yIEJydXNzZWxzLXJlZ2lvbiBpcyBub3QgaW5jbHVkZWQgaW4gcHJvdmVuY2VzLCBhZGQgZnJvbSByZWdpb24NCnByb3ZpbmNlcyA9IHJiaW5kKA0KICBwcm92aW5jZXMgJT4lIHNlbGVjdChDRF9QUk9WX1JFRk5JUywgVFhfUFJPVl9ERVNDUl9OTCksDQogIHJlZ2lvbnMgJT4lDQogICAgZmlsdGVyKFRYX1JHTl9ERVNDUl9OTCA9PSAiQnJ1c3NlbHMgSG9vZmRzdGVkZWxpamsgR2V3ZXN0IikgJT4lDQogICAgbXV0YXRlKENEX1JHTl9SRUZOSVMgPSAnMDQwMDAnKSAlPiUNCiAgICBzZWxlY3QoDQogICAgICBDRF9QUk9WX1JFRk5JUyA9IENEX1JHTl9SRUZOSVMsDQogICAgICBUWF9QUk9WX0RFU0NSX05MID0gVFhfUkdOX0RFU0NSX05MKSkNCmBgYA0KDQpgYGB7cn0NCnByb3ZpbmNlcyA9IHByb3ZpbmNlcyAlPiUNCiAgbXV0YXRlKENEX1BST1ZfUkVGTklTID0gYXMuY2hhcmFjdGVyKENEX1BST1ZfUkVGTklTKSkgJT4lDQogIGxlZnRfam9pbihkeW5hbS5wcm92LCBjKCdDRF9QUk9WX1JFRk5JUycgPSAncHJvdmluY2VfbmlzX2NvZGUnKSkNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBnZXQgY2VudHJvaWQgY29vcmRpbmF0ZXMgZm9yIGVhY2ggcHJvdmluY2UgdG8gcGxvdCBiYXJjaGFydCB0aGVyZQ0KcHJvdmluY2VzX2Nvb3JkcyA9IGFzX3RpYmJsZShzdF9jb29yZGluYXRlcyhzdF9jZW50cm9pZChwcm92aW5jZXMpKSkNCm5hbWVzKHByb3ZpbmNlc19jb29yZHMpIDwtIGMoJ2NlbnRyb2lkX2xvbmcnLCAnY2VudHJvaWRfbGF0JykNCnByb3ZpbmNlcyA8LSBiaW5kX2NvbHMocHJvdmluY2VzLCBwcm92aW5jZXNfY29vcmRzKQ0KYGBgDQoNCiMgRGVzY3JpcHRpdmUgZ3JhcGhzDQoNCiMjIE92ZXJsYXBwaW5nIGJhcmNoYXJ0IGV4YW1wbGUNCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsIGZpZy5hbGlnbj0nY2VudGVyJ30NCiMgT3ZlcmxhcHBpbmcgYmFyY2hhcnRzOg0KIyBodHRwOi8vc3RlcGhhbmllZXZlcmdyZWVuLmNvbS9vdmVybGFwcGluZy1iYXJzLw0KIyBodHRwczovL2dpc3QuZ2l0aHViLmNvbS9ocmJybXN0ci8wMzVmOTk4NTE3ZGUyMzg0ZTk5NjJjZmY3ZGY4NzRiZA0KIyANCg0KZ2cgPC0gZ2dwbG90KGRhdGE9ZHluYW0ucHJvdiwgYWVzKHk9cHJvdmluY2VfbGJsX3BjdCwgeWVuZD1wcm92aW5jZV9sYmxfcGN0KSkNCmdnIDwtIGdnICsgZ2VvbV9zZWdtZW50KGFlcyh4PWJydXRvX2FmbmFtZV9hYnNvbHV1dCwgeGVuZD0wLCBjb2xvcj0iSm9idmVybGllcyIpLCBzaXplPTEwKQ0KZ2cgPC0gZ2cgKyBnZW9tX3NlZ21lbnQoYWVzKHg9YnJ1dG9fdG9lbmFtZV9hYnNvbHV1dCwgeGVuZD0wLCBjb2xvcj0iSm9iZ3JvZWkiKSwgc2l6ZT01KQ0KZ2cgPC0gZ2cgKyBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzPWZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBkZWNpbWFsLm1hcmsgPSAnLCcsIGJpZy5tYXJrID0gIi4iLCBzY2llbnRpZmljID0gRkFMU0UpKQ0KZ2cgPC0gZ2cgKyBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9YyhKb2J2ZXJsaWVzPSIjYmViZWJmIiwgSm9iZ3JvZWk9IiMxMDc0YmMiKSkNCmdnIDwtIGdnICsgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChrZXl3aWR0aD0wLCBvdmVycmlkZS5hZXM9bGlzdChzaXplPTQpKSkNCmdnIDwtIGdnICsgbGFicygNCiAgeD1OVUxMLCB5PU5VTEwsDQogIHRpdGxlPSJBbGxlIHByb3ZpbmNpZXMga2VubmVuIGVlbiBuZXR0byBqb2JhYW5ncm9laSwgbWV0IGRlIGdyb290c3RlXG5wcm9jZW50dWVsZSBncm9laSBpbiBOYW1lbiIsDQogIHN1YnRpdGxlID0gJ1Byb2NlbnR1ZWxlIGVuIGFic29sdXRlIGpvYmV2b2x1dGllIHBlciBwcm92aW5jaWUsIDIwMTYtMjAxNycsDQogIGNhcHRpb249IkJyb246IEhJVkEtS1UgTGV1dmVuIHwgRHluYU0gfCBkeW5hbXJlc2VhcmNoLmJlIikNCmdnIDwtIGdnICsgdGhlbWVfbWluaW1hbCgpDQpnZyA8LSBnZyArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChtYXJnaW49bWFyZ2luKHQ9MCkpKQ0KZ2cgPC0gZ2cgKyB0aGVtZShheGlzLnRleHQueT1lbGVtZW50X3RleHQobWFyZ2luPW1hcmdpbihyPS0xMCkpKQ0KZ2cgPC0gZ2cgKyB0aGVtZShwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSkNCmdnIDwtIGdnICsgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55PWVsZW1lbnRfYmxhbmsoKSkNCmdnIDwtIGdnICsgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQ0KZ2cgPC0gZ2cgKyB0aGVtZShwbG90Lm1hcmdpbj1tYXJnaW4oMjAsMjAsMjAsMjApKQ0KZ2cgPC0gZ2cgKyB0aGVtZShwbG90LmNhcHRpb249ZWxlbWVudF90ZXh0KHNpemU9OCwgbWFyZ2luPW1hcmdpbih0PTEwLCByPTApKSkNCmdnIDwtIGdnICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPWMoMC44LCAwLjkpKQ0KZ2cgPC0gZ2cgKyB0aGVtZShsZWdlbmQuZGlyZWN0aW9uPSJ2ZXJ0aWNhbCIpDQpnZyA8LSBnZyArIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIsIGNvbG9yPSJ3aGl0ZSIpKQ0KZ2cNCmBgYA0KDQojIFN0YXRpYyBtYXAgdmlzdWFsaXNhdGlvbnMNCg0KIyMgSW5rbGV1cmVuIGJydXRvIHRvZW5hbWUNCg0KYGBge3J9DQp0bV9zaGFwZShwcm92aW5jZXMpICsNCiAgdG1fcG9seWdvbnMoY29sID0gJ2JydXRvX3RvZW5hbWVfcGN0JywgcGFsZXR0ZSA9ICdHcmVlbnMnLCBib3JkZXIuY29sID0gJ3doaXRlJywgdGl0bGUgPSAnQnJ1dG8gam9idG9lbmFtZSAoJSknKQ0KYGBgDQoNCiMjIElua2xldXJlbiBicnV0byBhZm5hbWUNCg0KYGBge3J9DQp0bV9zaGFwZShwcm92aW5jZXMpICsNCiAgdG1fcG9seWdvbnMoY29sID0gJ2JydXRvX2FmbmFtZV9wY3QnLCBwYWxldHRlID0gJ1JlZHMnLCBib3JkZXIuY29sID0gJ3doaXRlJywgdGl0bGUgPSAnQnJ1dG8gam9iYWZuYW1lICglKScpDQpgYGANCg0KIyMgSW5rbGV1cmVuIG5ldHRvIGV2b2x1dGllDQoNCmBgYHtyfQ0KdG1fc2hhcGUocHJvdmluY2VzKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICduZXR0b19wY3QnLCBwYWxldHRlID0gJ0dyZWVucycsIGJvcmRlci5jb2wgPSAnd2hpdGUnLCB0aXRsZSA9ICdOZXR0byBqb2Jldm9sdXRpZSAoJSknKQ0KYGBgDQoNCiMjIElua2xldXJlbiBicnV0byBqb2J0b2VuYW1lICsgZXhhY3QgY2lqZmVyDQoNCmBgYHtyfQ0KdG1fc2hhcGUocHJvdmluY2VzICU+JSBtdXRhdGUoYnJ1dG9fdG9lbmFtZV9wY3QgPSByb3VuZChicnV0b190b2VuYW1lX3BjdCwgMikpKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICdicnV0b190b2VuYW1lX3BjdCcsIHBhbGV0dGUgPSAnR3JlZW5zJywgYm9yZGVyLmNvbCA9ICd3aGl0ZScsIHRpdGxlID0gJ0JydXRvIGpvYnRvZW5hbWUgKCUpJykgKw0KICB0bV90ZXh0KCdicnV0b190b2VuYW1lX3BjdCcsIHNpemU9IC43KQ0KYGBgDQoNCiMjIElua2xldXJlbiBicnV0byBqb2JhZm5hbWUgKyBleGFjdCBjaWpmZXINCg0KYGBge3J9DQp0bV9zaGFwZShwcm92aW5jZXMgJT4lIG11dGF0ZShicnV0b19hZm5hbWVfcGN0ID0gcm91bmQoYnJ1dG9fYWZuYW1lX3BjdCwgMikpKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICdicnV0b19hZm5hbWVfcGN0JywgcGFsZXR0ZSA9ICdSZWRzJywgYm9yZGVyLmNvbCA9ICd3aGl0ZScsIHRpdGxlID0gJ0JydXRvIGpvYmFmbmFtZSAoJSknKSArDQogIHRtX3RleHQoJ2JydXRvX2FmbmFtZV9wY3QnLCBzaXplPSAuNykNCmBgYA0KDQojIyBJbmtsZXVyZW4gbmV0dG8gZXZvbHV0aWUgKyBleGFjdCBjaWpmZXINCg0KYGBge3J9DQp0bV9zaGFwZShwcm92aW5jZXMgJT4lIG11dGF0ZShuZXR0b19wY3QgPSByb3VuZChuZXR0b19wY3QsIDIpKSkgKw0KICB0bV9wb2x5Z29ucyhjb2wgPSAnbmV0dG9fcGN0JywgcGFsZXR0ZSA9ICdHcmVlbnMnLCBib3JkZXIuY29sID0gJ3doaXRlJywgdGl0bGUgPSAnTmV0dG8gam9iZXZvbHV0aWUgKCUpJykgKw0KICB0bV90ZXh0KCduZXR0b19wY3QnLCBzaXplPSAuNykNCmBgYA0KDQojIEludGVyYWN0aXZlIG1hcCB2aXN1YWxpc2F0aW9ucw0KDQojIyBBY2h0ZXJncm9uZGtsZXVyIG5ldHRvLWV2b2x1dGllICglKSArIGNpamZlcnMgaW4gbW91c2Utb3ZlciBwb3B1cA0KDQpgYGB7cn0NCmJpbnMgPC0gYygwLjAsIDAuNSwgMSwgMS41LCAyLjAsIDIuNSkNCnBhbF9ncmVlbnNfbmV0dG8gPC0gY29sb3JCaW4oIkdyZWVucyIsIGRvbWFpbiA9IHByb3ZpbmNlcyRuZXR0b19wY3QsIGJpbnMgPSBiaW5zKQ0KDQpwcm92aW5jZXMgPC0gcHJvdmluY2VzICU+JQ0KICBtdXRhdGUocG9wdXBfbGJsID0gc3RyX2dsdWUoIjxoMz57cHJvdmluY2VfbGJsfTwvaDM+PGJyIC8+PGI+Sm9idG9lbmFtZTogPC9iPntuZXR0b19wY3R9IikpDQoNCmxhYmVscyA8LSBzcHJpbnRmKA0KICAiPHN0cm9uZz4lczwvc3Ryb25nPjxici8+Sm9idG9lbmFtZTogJTEuMmYlJTxici8+Sm9iYWZuYW1lOiAlMS4yZiUlPGJyLz5OZXR0byBldm9sdXRpZTogJTEuMmYlJTxici8+IiwNCiAgcHJvdmluY2VzJHByb3ZpbmNlX2xibCwgcHJvdmluY2VzJGJydXRvX3RvZW5hbWVfcGN0LCBwcm92aW5jZXMkYnJ1dG9fYWZuYW1lX3BjdCwgcHJvdmluY2VzJG5ldHRvX3BjdA0KKSAlPiUgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkNCg0KbWFwX3RpdGxlIDwtIHRhZ3MkZGl2KA0KICBIVE1MKCc8Yj5OZXR0byBqb2Jldm9sdXRpZSBwZXIgcHJvdmluY2llLCAyMDE1LTIwMTYgKDxhIGhyZWY9Imh0dHBzOi8vZHluYW1yZXNlYXJjaC5iZS8iPmR5bmFNPC9hPik8L2I+JykNCikgIA0KDQptLmR5bmFtLnByb3YubmV0dG8uaG92ZXIgPC0gbGVhZmxldChwcm92aW5jZXMpICU+JQ0KICAjIHNldFZpZXcoLTk2LCAzNy44LCA0KSAlPiUNCiAgYWRkUG9seWdvbnMoDQogICAgZmlsbENvbG9yID0gfnBhbF9ncmVlbnNfbmV0dG8obmV0dG9fcGN0KSwNCiAgICB3ZWlnaHQgPSAyLA0KICAgIG9wYWNpdHkgPSAxLA0KICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICBkYXNoQXJyYXkgPSAiMyIsDQogICAgZmlsbE9wYWNpdHkgPSAwLjcsDQogICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucygNCiAgICAgIHdlaWdodCA9IDUsDQogICAgICBjb2xvciA9ICIjNjY2IiwNCiAgICAgIGRhc2hBcnJheSA9ICIiLA0KICAgICAgZmlsbE9wYWNpdHkgPSAwLjcsDQogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwNCiAgICBsYWJlbCA9IGxhYmVscywNCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoDQogICAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiLCBwYWRkaW5nID0gIjNweCA4cHgiKSwNCiAgICAgIHRleHRzaXplID0gIjE1cHgiLA0KICAgICAgZGlyZWN0aW9uID0gImF1dG8iKSkgJT4lDQogIGFkZExlZ2VuZCgNCiAgICB0aXRsZSA9ICdKb2Jldm9sdXRpZSAoJSknLA0KICAgIHBhbCA9IHBhbF9ncmVlbnNfbmV0dG8sIHZhbHVlcyA9IH5uZXR0b19wY3QsIG9wYWNpdHkgPSAwLjcsDQogICAgICAgICAgICBwb3NpdGlvbiA9ICJ0b3ByaWdodCIpICU+JQ0KICBhZGRDb250cm9sKG1hcF90aXRsZSwgcG9zaXRpb24gPSAiYm90dG9tbGVmdCIpDQoNCm0uZHluYW0ucHJvdi5uZXR0by5ob3Zlcg0KYGBgDQoNCiMjIEFjaHRlcmdyb25ka2xldXIgYnJ1dG8tdG9lbmFtZSAoJSkgKyBjaWpmZXJzIGluIG1vdXNlLW92ZXIgcG9wdXANCg0KYGBge3J9DQpiaW5zIDwtIGMoNCwgNSwgNiwgNywgOCkNCnBhbF9ncmVlbnNfdG9lbmFtZSA8LSBjb2xvckJpbigiR3JlZW5zIiwgZG9tYWluID0gcHJvdmluY2VzJGJydXRvX3RvZW5hbWVfcGN0LCBiaW5zID0gYmlucykNCg0KbWFwX3RpdGxlIDwtIHRhZ3MkZGl2KA0KICBIVE1MKCc8Yj5CcnV0byBqb2J0b2VuYW1lIHBlciBwcm92aW5jaWUsIDIwMTUtMjAxNiAoPGEgaHJlZj0iaHR0cHM6Ly9keW5hbXJlc2VhcmNoLmJlLyI+ZHluYU08L2E+KTwvYj4nKQ0KKQ0KDQptLmR5bmFtLnByb3YudG9lbmFtZS5ob3ZlciA8LSBsZWFmbGV0KHByb3ZpbmNlcykgJT4lDQogICMgc2V0VmlldygtOTYsIDM3LjgsIDQpICU+JQ0KICBhZGRQb2x5Z29ucygNCiAgICBmaWxsQ29sb3IgPSB+cGFsX2dyZWVuc190b2VuYW1lKGJydXRvX3RvZW5hbWVfcGN0KSwNCiAgICB3ZWlnaHQgPSAyLA0KICAgIG9wYWNpdHkgPSAxLA0KICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICBkYXNoQXJyYXkgPSAiMyIsDQogICAgZmlsbE9wYWNpdHkgPSAwLjcsDQogICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucygNCiAgICAgIHdlaWdodCA9IDUsDQogICAgICBjb2xvciA9ICIjNjY2IiwNCiAgICAgIGRhc2hBcnJheSA9ICIiLA0KICAgICAgZmlsbE9wYWNpdHkgPSAwLjcsDQogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwNCiAgICBsYWJlbCA9IGxhYmVscywNCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoDQogICAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiLCBwYWRkaW5nID0gIjNweCA4cHgiKSwNCiAgICAgIHRleHRzaXplID0gIjE1cHgiLA0KICAgICAgZGlyZWN0aW9uID0gImF1dG8iKSkgJT4lDQogIGFkZExlZ2VuZCgNCiAgICB0aXRsZSA9ICdCcnV0byBqb2J0b2VuYW1lICglKScsDQogICAgcGFsID0gcGFsX2dyZWVuc190b2VuYW1lLCB2YWx1ZXMgPSB+YnJ1dG9fdG9lbmFtZV9wY3QsIG9wYWNpdHkgPSAwLjcsDQogICAgICAgICAgICBwb3NpdGlvbiA9ICJ0b3ByaWdodCIpICU+JQ0KICBhZGRDb250cm9sKG1hcF90aXRsZSwgcG9zaXRpb24gPSAiYm90dG9tbGVmdCIpDQoNCm0uZHluYW0ucHJvdi50b2VuYW1lLmhvdmVyDQpgYGANCg0KIyMgQWNodGVyZ3JvbmRrbGV1ciBicnV0by1hZm5hbWUgKCUpICsgY2lqZmVycyBpbiBtb3VzZS1vdmVyIHBvcHVwDQoNCmBgYHtyfQ0KYmlucyA8LSBjKDQsIDUsIDYsIDcsIDgpDQpwYWxfZ3JlZW5zX2FmbmFtZSA8LSBjb2xvckJpbigiUmVkcyIsIGRvbWFpbiA9IHByb3ZpbmNlcyRicnV0b190b2VuYW1lX3BjdCwgYmlucyA9IGJpbnMpDQoNCm1hcF90aXRsZSA8LSB0YWdzJGRpdigNCiAgSFRNTCgnPGI+QnJ1dG8gam9iYWZuYW1lIHBlciBwcm92aW5jaWUsIDIwMTUtMjAxNiAoPGEgaHJlZj0iaHR0cHM6Ly9keW5hbXJlc2VhcmNoLmJlLyI+ZHluYU08L2E+KTwvYj4nKQ0KKQ0KDQptLmR5bmFtLnByb3YuYWZuYW1lLmhvdmVyIDwtIGxlYWZsZXQocHJvdmluY2VzKSAlPiUNCiAgIyBzZXRWaWV3KC05NiwgMzcuOCwgNCkgJT4lDQogIGFkZFBvbHlnb25zKA0KICAgIGZpbGxDb2xvciA9IH5wYWxfZ3JlZW5zX2FmbmFtZShicnV0b190b2VuYW1lX3BjdCksDQogICAgd2VpZ2h0ID0gMiwNCiAgICBvcGFjaXR5ID0gMSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMoDQogICAgICB3ZWlnaHQgPSA1LA0KICAgICAgY29sb3IgPSAiIzY2NiIsDQogICAgICBkYXNoQXJyYXkgPSAiIiwNCiAgICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksDQogICAgbGFiZWwgPSBsYWJlbHMsDQogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKA0KICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksDQogICAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwNCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JQ0KICBhZGRMZWdlbmQoDQogICAgdGl0bGUgPSAnQnJ1dG8gam9iYWZuYW1lICglKScsDQogICAgcGFsID0gcGFsX2dyZWVuc19hZm5hbWUsIHZhbHVlcyA9IH5icnV0b190b2VuYW1lX3BjdCwgb3BhY2l0eSA9IDAuNywNCiAgICAgICAgICAgIHBvc2l0aW9uID0gInRvcHJpZ2h0IikgJT4lDQogIGFkZENvbnRyb2wobWFwX3RpdGxlLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikNCg0KbS5keW5hbS5wcm92LmFmbmFtZS5ob3Zlcg0KYGBgDQoNCiMjIEFjaHRlcmdyb25ka2xldXIgbmV0dG8tZXZvbHV0aWUgKCUpICsgY2lqZmVycyBpbiBtb3VzZS1vdmVyIHBvcHVwICsgbmV0dG8tY2lqZmVyIHdlZXJnZXZlbg0KDQpgYGB7cn0NCmJpbnMgPC0gYygwLjAsIDAuNSwgMSwgMS41LCAyLjAsIDIuNSkNCnBhbF9ncmVlbnNfbmV0dG8gPC0gY29sb3JCaW4oIkdyZWVucyIsIGRvbWFpbiA9IHByb3ZpbmNlcyRuZXR0b19wY3QsIGJpbnMgPSBiaW5zKQ0KDQpwcm92aW5jZXMgPC0gcHJvdmluY2VzICU+JQ0KICBtdXRhdGUocG9wdXBfbGJsID0gc3RyX2dsdWUoIjxoMz57cHJvdmluY2VfbGJsfTwvaDM+PGJyIC8+PGI+Sm9idG9lbmFtZTogPC9iPntuZXR0b19wY3R9IikpDQoNCmxhYmVscyA8LSBzcHJpbnRmKA0KICAiPHN0cm9uZz4lczwvc3Ryb25nPjxici8+Sm9idG9lbmFtZTogJTEuMmYlJTxici8+Sm9iYWZuYW1lOiAlMS4yZiUlPGJyLz5OZXR0byBldm9sdXRpZTogJTEuMmYlJTxici8+IiwNCiAgcHJvdmluY2VzJHByb3ZpbmNlX2xibCwgcHJvdmluY2VzJGJydXRvX3RvZW5hbWVfcGN0LCBwcm92aW5jZXMkYnJ1dG9fYWZuYW1lX3BjdCwgcHJvdmluY2VzJG5ldHRvX3BjdA0KKSAlPiUgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkNCg0KbWFwX3RpdGxlIDwtIHRhZ3MkZGl2KA0KICBIVE1MKCc8Yj5OZXR0byBqb2Jldm9sdXRpZSBwZXIgcHJvdmluY2llLCAyMDE1LTIwMTYgKDxhIGhyZWY9Imh0dHBzOi8vZHluYW1yZXNlYXJjaC5iZS8iPmR5bmFNPC9hPik8L2I+JykNCikgIA0KDQptLmR5bmFtLnByb3YubmV0dG8uaG92ZXIubnVtYmVyIDwtIGxlYWZsZXQocHJvdmluY2VzKSAlPiUNCiAgIyBzZXRWaWV3KC05NiwgMzcuOCwgNCkgJT4lDQogIGFkZFBvbHlnb25zKA0KICAgIGZpbGxDb2xvciA9IH5wYWxfZ3JlZW5zX25ldHRvKG5ldHRvX3BjdCksDQogICAgd2VpZ2h0ID0gMiwNCiAgICBvcGFjaXR5ID0gMSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMoDQogICAgICB3ZWlnaHQgPSA1LA0KICAgICAgY29sb3IgPSAiIzY2NiIsDQogICAgICBkYXNoQXJyYXkgPSAiIiwNCiAgICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksDQogICAgbGFiZWwgPSBsYWJlbHMsDQogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKA0KICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksDQogICAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwNCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JQ0KICBhZGRMZWdlbmQoDQogICAgdGl0bGUgPSAnSm9iZXZvbHV0aWUgKCUpJywNCiAgICBwYWwgPSBwYWxfZ3JlZW5zX25ldHRvLCB2YWx1ZXMgPSB+bmV0dG9fcGN0LCBvcGFjaXR5ID0gMC43LA0KICAgICAgICAgICAgcG9zaXRpb24gPSAidG9wcmlnaHQiKSAlPiUNCiAgYWRkQ29udHJvbChtYXBfdGl0bGUsIHBvc2l0aW9uID0gImJvdHRvbWxlZnQiKQ0KDQptLmR5bmFtLnByb3YubmV0dG8uaG92ZXIubnVtYmVyID0gbS5keW5hbS5wcm92Lm5ldHRvLmhvdmVyLm51bWJlciAlPiUNCiAgYWRkTGFiZWxPbmx5TWFya2VycyhsbmcgPSB+Y2VudHJvaWRfbG9uZywgbGF0ID0gfmNlbnRyb2lkX2xhdCwgDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAgfmFzLmNoYXJhY3Rlcihyb3VuZChuZXR0b19wY3QsMikpLCANCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gVCwgZGlyZWN0aW9uID0gJ3RvcCcsIHRleHRPbmx5ID0gVCkpDQoNCm0uZHluYW0ucHJvdi5uZXR0by5ob3Zlci5udW1iZXINCg0KYGBgDQoNCg0KIyMgQWNodGVyZ3JvbmQgbmV0dG9ldm9sdXRpZSArIGNsaWNrYWJsZSBiYXJjaGFydCBtZXQgYWJzb2x1dGUgZXZvbHV0aWUgDQoNCmBgYHtyfQ0KcGFsIDwtIGNvbG9yQmluKCJHcmVlbnMiLCBkb21haW4gPSBkeW5hbS5wcm92JG5ldHRvX3BjdCkNCmBgYA0KDQoNCmBgYHtyfQ0KZC5hYnMgPSBkeW5hbS5wcm92ICU+JQ0KICBzZWxlY3QoDQogICAgJ0pvYmdyb2VpJyA9IGJydXRvX3RvZW5hbWVfYWJzb2x1dXQsDQogICAgJ0pvYnZlcmxpZXMnID0gYnJ1dG9fYWZuYW1lX2Fic29sdXV0X25lZywNCiAgICAnTmV0dG8gam9iZXZvbHV0aWUnID0gbmV0dG9fYWJzb2x1dXQpDQoNCmQucGN0ID0gZHluYW0ucHJvdiAlPiUNCiAgbXV0YXRlKA0KICAgIGJydXRvX3RvZW5hbWVfcGN0ID0gcm91bmQoYnJ1dG9fdG9lbmFtZV9wY3QsMiksDQogICAgYnJ1dG9fYWZuYW1lX3BjdCA9IHJvdW5kKGJydXRvX2FmbmFtZV9wY3QqLTEsMiksDQogICAgbmV0dG9fcGN0ID0gcm91bmQobmV0dG9fcGN0LDIpKSAlPiUNCnNlbGVjdCgNCiAgJ0pvYmdyb2VpJyA9IGJydXRvX3RvZW5hbWVfcGN0LA0KICAnSm9idmVybGllcycgPSBicnV0b19hZm5hbWVfcGN0LA0KICAnTmV0dG8gam9iZXZvbHV0aWUnID0gbmV0dG9fcGN0KQ0KYGBgDQoNCg0KYGBge3IgcmVzdWx0cz0iYXNpcyIsIGVjaG89RkFMU0V9DQpjYXQoIg0KPHN0eWxlPg0KLmxlYWZsZXQtY29udGFpbmVyIHsNCiAgICBiYWNrZ3JvdW5kOiAjRkZGOw0KfQ0KPC9zdHlsZT4NCiIpDQpgYGANCg0KYGBge3J9DQptLnByb3YgPSBsZWFmbGV0KHByb3ZpbmNlcywgd2lkdGggPSAnMTAwJScpICU+JSANCiAgIyBhZGQgZ3JleSBhcnJvbmRpc3NlbWVudCBwb2x5Z29ucyB3L3Qgd2hpdGUgYm9yZGVyDQogIGFkZFBvbHlnb25zKA0KICAgIHdlaWdodCA9IDIsDQogICAgb3BhY2l0eSA9IDEsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxDb2xvciA9IH5wYWwobmV0dG9fcGN0KSwgY29sb3IgPSAnd2hpdGUnKSAlPiUgDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5uZXR0b19hYnNvbHV1dCwgb3BhY2l0eSA9IDAuNywNCiAgICAgICAgICAgIHRpdGxlID0gJ05ldHRvIGpvYmV2b2x1dGllICglKScsDQogIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IikNCg0KY29sb3JzIDwtIGMoIiM3Y2FlMDAiLCAiI2Y4NzY2ZCIsICIjYzc3Y2ZmIikNCm0ucHJvdiA9IG0ucHJvdiAlPiUNCiAgYWRkTWluaWNoYXJ0cygNCiAgICBwcm92aW5jZXNfY29vcmRzJGNlbnRyb2lkX2xvbmcsIHByb3ZpbmNlc19jb29yZHMkY2VudHJvaWRfbGF0LA0KICAgIGNoYXJ0ZGF0YSA9IGQuYWJzLA0KICAgIGNvbG9yUGFsZXR0ZSA9IGNvbG9ycywNCiAgICB3aWR0aCA9IDQ1LCBoZWlnaHQgPSA0NSkNCg0KbWFwX3RpdGxlIDwtIHRhZ3MkZGl2KA0KICAgSFRNTCgnPGI+QnJ1dG8gZW4gbmV0dG8gam9iZXZvbHV0aWUgcGVyIHByb3ZpbmNpZSwgMjAxNy0yMDE4ICg8YSBocmVmPSJodHRwczovL2R5bmFtcmVzZWFyY2guYmUvIj5EeW5hTTwvYT4pPC9iPicpDQogKSAgDQoNCm0ucHJvdiA9IG0ucHJvdiAlPiUgDQogIGFkZENvbnRyb2wobWFwX3RpdGxlLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikNCg0KbS5wcm92DQoNCmBgYA0KDQoNCmBgYHtyfQ0KbS5keWFtLmJhci5uZXR0by5wY3QgPSBsZWFmbGV0KHByb3ZpbmNlcywgd2lkdGggPSAnMTAwJScpICU+JSANCiAgIyBhZGQgZ3JleSBhcnJvbmRpc3NlbWVudCBwb2x5Z29ucyB3L3Qgd2hpdGUgYm9yZGVyDQogIGFkZFBvbHlnb25zKA0KICAgIHdlaWdodCA9IDIsDQogICAgb3BhY2l0eSA9IDEsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxDb2xvciA9IH5wYWwobmV0dG9fcGN0KSwgY29sb3IgPSAnd2hpdGUnKSAlPiUgDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5uZXR0b19wY3QsIG9wYWNpdHkgPSAwLjcsDQogICAgICAgICAgICB0aXRsZSA9ICdOZXR0byBqb2Jldm9sdXRpZSAoJSknLA0KICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIpDQoNCmNvbG9ycyA8LSBjKCIjN2NhZTAwIiwgIiNmODc2NmQiLCAiI2M3N2NmZiIpDQptLmR5YW0uYmFyLm5ldHRvLnBjdCA9IG0uZHlhbS5iYXIubmV0dG8ucGN0ICU+JQ0KICBhZGRNaW5pY2hhcnRzKA0KICAgIHByb3ZpbmNlc19jb29yZHMkY2VudHJvaWRfbG9uZywgcHJvdmluY2VzX2Nvb3JkcyRjZW50cm9pZF9sYXQsDQogICAgY2hhcnRkYXRhID0gZC5wY3QsDQogICAgY29sb3JQYWxldHRlID0gY29sb3JzLA0KICAgIHdpZHRoID0gNDUsIGhlaWdodCA9IDQ1KQ0KDQptYXBfdGl0bGUgPC0gdGFncyRkaXYoDQogICBIVE1MKCc8Yj5CcnV0byBlbiBuZXR0byBqb2Jldm9sdXRpZSBwZXIgcHJvdmluY2llLCAyMDE3LTIwMTggKDxhIGhyZWY9Imh0dHBzOi8vZHluYW1yZXNlYXJjaC5iZS8iPkR5bmFNPC9hPik8L2I+JykNCiApICANCg0KbS5keWFtLmJhci5uZXR0by5wY3QgPSBtLmR5YW0uYmFyLm5ldHRvLnBjdCAlPiUgDQogIGFkZENvbnRyb2wobWFwX3RpdGxlLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikNCg0KbS5keWFtLmJhci5uZXR0by5wY3QNCg0KYGBgDQoNCmBgYHtyfQ0KIyBzYXZlV2lkZ2V0KA0KIyAgIG0uZHluYW0ucHJvdiwgZmlsZSA9IGhlcmU6OmhlcmUoJ2R5bmFtX2pvYmV2b2x1dGlvbicsICdkeW5hbV9uZXR0b19tYXBfc2VsZmNvbnRhaW5lZC5odG1sJyksIA0KIyAgIHNlbGZjb250YWluZWQgPSBUUlVFLA0KIyAgIGJhY2tncm91bmQgPSAnd2hpdGUnKQ0KIyANCiMgc2F2ZVdpZGdldCgNCiMgICBtLmR5bmFtLnByb3YsIGZpbGUgPSBoZXJlOjpoZXJlKCdkeW5hbV9qb2Jldm9sdXRpb24nLCAnZHluYW1fbmV0dG9fbWFwX25vdHNlbGZjb250YWluZWQuaHRtbCcpLCANCiMgICBzZWxmY29udGFpbmVkID0gRkFMU0UsDQojICAgYmFja2dyb3VuZCA9ICd3aGl0ZScpDQpgYGANCg0K